package com.qs.javame.thread.tool;

import java.util.Map;
import java.util.Random;
import java.util.concurrent.*;

/**
 * 测试：CyclicBarrier的基本使用
 * <p>
 * 使用：
 * 1）构造方法中设定同步屏障数；
 * 2）线程任务中调用await()方法，表示当前线程到达设定的屏障处，等待其他线程到达；
 * 3）所有线程都到达执行的屏障处，若构造方法中指定了barrierAction，则执行barrierAction中的线程任务；若没有，则从每个线程await()方法
 * 处返回，继续执行各自的线程任务。
 */
public class CyclicBarrierTest {

    //初始化同步屏障对象，设定2个同步点，就是当2个线程都到达设定的同步点后，线程继续执行。
    private static CyclicBarrier cyclicBarrier = new CyclicBarrier(2);

    public static void main(String[] args) {
        Thread thread = new Thread(() -> {
            try {
                //一个线程到达屏障(同步点)
                cyclicBarrier.await();
            } catch (InterruptedException | BrokenBarrierException e) {
                e.printStackTrace();
            }

            System.out.println(1);
        });

        thread.start();

        try {
            //main线程到达屏障
            cyclicBarrier.await();
        } catch (InterruptedException | BrokenBarrierException e) {
            e.printStackTrace();
        }

        System.out.println(2);
    }
}


/**
 * 测试：构造方法CyclicBarrier(int parties, Runnable barrierAction)
 */
class CyclicBarrierTest2 {

    //构造方法CyclicBarrier(int parties, Runnable barrierAction)，在线程到达同步屏障时，优先执行barrierAction，
    // 方便处理更复杂的业务场景
    private static CyclicBarrier cyclicBarrier = new CyclicBarrier(2, new Task());


    public static void main(String[] args) {
        new Thread(() -> {
            try {
                cyclicBarrier.await();
            } catch (InterruptedException | BrokenBarrierException e) {
                e.printStackTrace();
            }

            System.out.println(1);
        }).start();

        try {
            cyclicBarrier.await();
        } catch (InterruptedException | BrokenBarrierException e) {
            e.printStackTrace();
        }

        System.out.println(2);
    }


    static class Task implements Runnable {
        @Override
        public void run() {
            System.out.println(3);
        }
    }
}


/**
 * 应用场景：CyclicBarrier可以用于多线程计算数据，最后合并计算结果的场景。
 * 如：计算Excel多个sheet中银行流水信息，每个sheet对应一个线程，最后在barrierAction中计算汇总的结果。
 */
class BankWaterService implements Runnable {

    //创建4个屏障，处理完之后执行当前类的run方法
    private CyclicBarrier cyclicBarrier = new CyclicBarrier(4, this);

    //假设有4个sheet，线程池中初始化4个线程
    private Executor executor = Executors.newFixedThreadPool(4);

    //保存每个sheet计算出的结果
    private ConcurrentHashMap<String, Integer> sheetBankWaterCount = new ConcurrentHashMap<>();


    public static void main(String[] args) {
        BankWaterService bankWaterService = new BankWaterService();

        bankWaterService.count();
    }


    private void count() {
        for (int i = 0; i < 4; i++) {
            executor.execute(() -> {
                //将每个线程计算的值存储map中
                sheetBankWaterCount.put(Thread.currentThread().getName(), 1);
                try {
                    cyclicBarrier.await();
                } catch (InterruptedException | BrokenBarrierException e) {
                    e.printStackTrace();
                }
            });
        }
    }


    private int getSheetCount(int sheetNum) {
        Random random = new Random(100);
        return random.nextInt();
    }

    @Override
    public void run() {
        int result = 0;
        for (Map.Entry<String, Integer> entry : sheetBankWaterCount.entrySet()) {
            result += entry.getValue();
        }

        sheetBankWaterCount.put("result", result);
        System.out.println("result=" + result);
    }
}
